<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------

/**
 * ThinkPHP Action控制器基类 精简模式
 * @category   Think
 * @package  Think
 * @subpackage  Core
 * @author   liu21st <liu21st@gmail.com>
 */
abstract class Action {

	// 当前Action名称
	private $name   = '';
	protected $tVar = array(); // 模板输出变量

	/**
	 * 架构函数 取得模板对象实例
	 * @access public
	 */
	public function __construct() {
		tag('action_begin');
		//控制器初始化
		if (method_exists($this, '_initialize')) {
			$this->_initialize();
		}

	}

	/**
	 * 获取当前Action名称
	 * @access protected
	 */
	protected function getActionName() {
		if (empty($this->name)) {
			// 获取Action名称
			$this->name = substr(get_class($this), 0, -6);
		}
		return $this->name;
	}

	/**
	 * 是否AJAX请求
	 * @access protected
	 * @return bool
	 */
	protected function isAjax() {
		if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
			if ('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) {
				return true;
			}

		}
		if (!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')]))
		// 判断Ajax方式提交
		{
			return true;
		}

		return false;
	}

	/**
	 * 模板变量赋值
	 * @access public
	 * @param mixed $name
	 * @param mixed $value
	 */
	public function assign($name, $value = '') {
		if (is_array($name)) {
			$this->tVar = array_merge($this->tVar, $name);
		} elseif (is_object($name)) {
			foreach ($name as $key => $val) {
				$this->tVar[$key] = $val;
			}

		} else {
			$this->tVar[$name] = $value;
		}
	}

	public function __set($name, $value) {
		$this->assign($name, $value);
	}

	/**
	 * 取得模板变量的值
	 * @access public
	 * @param string $name
	 * @return mixed
	 */
	public function get($name) {
		if (isset($this->tVar[$name])) {
			return $this->tVar[$name];
		} else {
			return false;
		}

	}

	/**
	 * 魔术方法 有不存在的操作的时候执行
	 * @access public
	 * @param string $method 方法名
	 * @param array $args 参数
	 * @return mixed
	 */
	public function __call($method, $args) {
		if (0 === strcasecmp($method, ACTION_NAME)) {
			if (method_exists($this, '_empty')) {
				// 如果定义了_empty操作 则调用
				$this->_empty($method, $args);
			} elseif (file_exists_case(C('TEMPLATE_NAME'))) {
				// 检查是否存在默认模版 如果有直接输出模版
				$this->display();
			} else {
				// 抛出异常
				throw_exception(L('_ERROR_ACTION_') . ACTION_NAME);
			}
		} else {
			switch (strtolower($method)) {
				// 判断提交方式
				case 'ispost':
				case 'isget':
				case 'ishead':
				case 'isdelete':
				case 'isput':
					return strtolower($_SERVER['REQUEST_METHOD']) == strtolower(substr($method, 2));
				// 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default);
				case '_get':$input = &$_GET;
					break;
				case '_post':$input = &$_POST;
					break;
				case '_put':parse_str(file_get_contents('php://input'), $input);
					break;
				case '_request':$input = &$_REQUEST;
					break;
				case '_session':$input = &$_SESSION;
					break;
				case '_cookie':$input = &$_COOKIE;
					break;
				case '_server':$input = &$_SERVER;
					break;
				case '_globals':$input = &$GLOBALS;
					break;
				default:
					throw_exception(__CLASS__ . ':' . $method . L('_METHOD_NOT_EXIST_'));
			}
			if (isset($input[$args[0]])) {
				// 取值操作
				$data    = $input[$args[0]];
				$filters = isset($args[1]) ? $args[1] : C('DEFAULT_FILTER');
				if ($filters) {
// 2012/3/23 增加多方法过滤支持
					$filters = explode(',', $filters);
					foreach ($filters as $filter) {
						if (function_exists($filter)) {
							$data = is_array($data) ? array_map($filter, $data) : $filter($data); // 参数过滤
						}
					}
				}
			} else {
				// 变量默认值
				$data = isset($args[2]) ? $args[2] : NULL;
			}
			return $data;
		}
	}

	/**
	 * 操作错误跳转的快捷方法
	 * @access protected
	 * @param string $message 错误信息
	 * @param string $jumpUrl 页面跳转地址
	 * @param Boolean $ajax 是否为Ajax方式
	 * @return void
	 */
	protected function error($message, $jumpUrl = '', $ajax = false) {
		$this->dispatchJump($message, 0, $jumpUrl, $ajax);
	}

	/**
	 * 操作成功跳转的快捷方法
	 * @access protected
	 * @param string $message 提示信息
	 * @param string $jumpUrl 页面跳转地址
	 * @param Boolean $ajax 是否为Ajax方式
	 * @return void
	 */
	protected function success($message, $jumpUrl = '', $ajax = false) {
		$this->dispatchJump($message, 1, $jumpUrl, $ajax);
	}

	/**
	 * Ajax方式返回数据到客户端
	 * @access protected
	 * @param mixed $data 要返回的数据
	 * @param String $info 提示信息
	 * @param boolean $status 返回状态
	 * @param String $status ajax返回类型 JSON XML
	 * @return void
	 */
	protected function ajaxReturn($data, $info = '', $status = 1, $type = '') {
		$result           = array();
		$result['status'] = $status;
		$result['info']   = $info;
		$result['data']   = $data;
		//扩展ajax返回数据, 在Action中定义function ajaxAssign(&$result){} 方法 扩展ajax返回数据。
		if (method_exists($this, "ajaxAssign")) {
			$this->ajaxAssign($result);
		}

		if (empty($type)) {
			$type = C('DEFAULT_AJAX_RETURN');
		}

		if (strtoupper($type) == 'JSON') {
			// 返回JSON数据格式到客户端 包含状态信息
			header("Content-Type:text/html; charset=utf-8");
			exit(json_encode($result));
		} elseif (strtoupper($type) == 'XML') {
			// 返回xml格式数据
			header("Content-Type:text/xml; charset=utf-8");
			exit(xml_encode($result));
		}
	}

	/**
	 * Action跳转(URL重定向） 支持指定模块和延时跳转
	 * @access protected
	 * @param string $url 跳转的URL表达式
	 * @param array $params 其它URL参数
	 * @param integer $delay 延时跳转的时间 单位为秒
	 * @param string $msg 跳转提示信息
	 * @return void
	 */
	protected function redirect($url, $params = array(), $delay = 0, $msg = '') {
		$url = U($url, $params);
		redirect($url, $delay, $msg);
	}

	/**
	 * 默认跳转操作 支持错误导向和正确跳转
	 * 调用模板显示 默认为public目录下面的success页面
	 * 提示页面为可配置 支持模板标签
	 * @param string $message 提示信息
	 * @param Boolean $status 状态
	 * @param string $jumpUrl 页面跳转地址
	 * @param Boolean $ajax 是否为Ajax方式
	 * @access private
	 * @return void
	 */
	private function dispatchJump($message, $status = 1, $jumpUrl = '', $ajax = false) {
		// 判断是否为AJAX返回
		if ($ajax || $this->isAjax()) {
			$this->ajaxReturn($ajax, $message, $status);
		}

		if (!empty($jumpUrl)) {
			$this->assign('jumpUrl', $jumpUrl);
		}

		// 提示标题
		$this->assign('msgTitle', $status ? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_'));
		//如果设置了关闭窗口，则提示完毕后自动关闭窗口
		if ($this->get('closeWin')) {
			$this->assign('jumpUrl', 'javascript:window.close();');
		}

		$this->assign('status', $status); // 状态
		//保证输出不受静态缓存影响
		C('HTML_CACHE_ON', false);
		if ($status) {
			//发送成功信息
			$this->assign('message', $message); // 提示信息
			// 成功操作后默认停留1秒
			if (!$this->get('waitSecond')) {
				$this->assign('waitSecond', "1");
			}

			// 默认操作成功自动返回操作前页面
			if (!$this->get('jumpUrl')) {
				$this->assign("jumpUrl", $_SERVER["HTTP_REFERER"]);
			}

			$this->display(C('TMPL_ACTION_SUCCESS'));
		} else {
			$this->assign('error', $message); // 提示信息
			//发生错误时候默认停留3秒
			if (!$this->get('waitSecond')) {
				$this->assign('waitSecond', "3");
			}

			// 默认发生错误的话自动返回上页
			if (!$this->get('jumpUrl')) {
				$this->assign('jumpUrl', "javascript:history.back(-1);");
			}

			$this->display(C('TMPL_ACTION_ERROR'));
			// 中止执行  避免出错后继续执行
			exit;
		}
	}

	/**
	 * 加载模板和页面输出 可以返回输出内容
	 * @access public
	 * @param string $templateFile 模板文件名
	 * @param string $charset 模板输出字符集
	 * @param string $contentType 输出类型
	 * @return mixed
	 */
	public function display($templateFile = '', $charset = '', $contentType = '') {
		G('viewStartTime');
		// 视图开始标签
		tag('view_begin', $templateFile);
		// 解析并获取模板内容
		$content = $this->fetch($templateFile);
		// 输出模板内容
		$this->show($content, $charset, $contentType);
		// 视图结束标签
		tag('view_end');
	}

	/**
	 * 输出内容文本可以包括Html
	 * @access public
	 * @param string $content 输出内容
	 * @param string $charset 模板输出字符集
	 * @param string $contentType 输出类型
	 * @return mixed
	 */
	public function show($content, $charset = '', $contentType = '') {
		if (empty($charset)) {
			$charset = C('DEFAULT_CHARSET');
		}

		if (empty($contentType)) {
			$contentType = C('TMPL_CONTENT_TYPE');
		}

		// 网页字符编码
		header("Content-Type:" . $contentType . "; charset=" . $charset);
		header("Cache-control: private"); //支持页面回跳
		header("X-Powered-By:TOPThink/" . THINK_VERSION);
		// 输出模板文件
		echo $content;
	}

	/**
	 * 解析和获取模板内容 用于输出
	 * @access public
	 * @param string $templateFile 模板文件名
	 * @return string
	 */
	public function fetch($templateFile = '') {
		// 模板文件解析标签
		tag('view_template', $templateFile);
		// 模板文件不存在直接返回
		if (!is_file($templateFile)) {
			return NULL;
		}

		// 页面缓存
		ob_start();
		ob_implicit_flush(0);
		// 视图解析标签
		$params = array('var' => $this->tVar, 'file' => $templateFile);
		$result = tag('view_parse', $params);
		if (false === $result) {
			// 未定义行为 则采用PHP原生模板
			// 模板阵列变量分解成为独立变量
			extract($this->tVar, EXTR_OVERWRITE);
			// 直接载入PHP模板
			include $templateFile;
		}
		// 获取并清空缓存
		$content = ob_get_clean();
		// 内容过滤标签
		tag('view_filter', $content);
		// 输出模板文件
		return $content;
	}

	/**
	 * 析构方法
	 * @access public
	 */
	public function __destruct() {
		// 保存日志
		if (C('LOG_RECORD')) {
			Log::save();
		}

		// 执行后续操作
		tag('action_end');
	}
}